﻿
using System;
using System.Collections.Generic;

using Bootstrap5.Abstractions;

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

namespace Bootstrap5;

/// <summary>
/// An input component used for selecting a value from a group of choices.
/// </summary>
/// <typeparam name="TValue">The type of the value.</typeparam>
[HtmlTag("input")]
[CssClass("form-check-input")]
public class FormInputRadio<TValue> : BootstrapComponentBase,IDisposable
{
    /// <summary>
    /// Initializes a new instance of <see cref="FormInputRadio{TValue}"/> class.
    /// </summary>
    public FormInputRadio()
    {
    }
    [CascadingParameter] FormInputGroup CascadedInputGroup { get; set; }
    /// <summary>
    /// Gets or sets the cascaded radio group.
    /// </summary>
    /// <value>
    /// The cascaded radio group.
    /// </value>
    [CascadingParameter] FormInputRadioGroup<TValue> CascadedRadioGroup { get; set; }

    /// <summary>
    /// Gets or sets the text displayed behind input tag.
    /// </summary>
    [Parameter] public string Text { get; set; }
    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    [Parameter] public TValue? Value { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }

    [Parameter] public bool Disabled { get; set; }

    protected override void OnInitialized()
    {
        if (CascadedRadioGroup == null)
        {
            throw new InvalidOperationException($"The '{nameof(FormInputRadio<TValue>)}' must inside of '{nameof(FormInputRadioGroup<TValue>)}' component");
        }
    }

    /// <summary>
    /// Method invoked when the component has received parameters from its parent in
    /// the render tree, and the incoming values have been assigned to properties.
    /// </summary>
    /// <exception cref="InvalidOperationException">
    /// </exception>
    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        Id = $"radio_{CascadedRadioGroup.Name}_" + Guid.NewGuid().ToString();

        if (Value?.GetType() != typeof(TValue))
        {
            throw new InvalidOperationException($"The type of {nameof(this.Value)} should be the same type of {typeof(FormInputRadio<>).FullName}");
        }
        if (CascadedRadioGroup.Readonly)
        {
            AdditionalAttributes["readonly"] = true;
        }
        if (CascadedRadioGroup.Disabled|| Disabled)
        {
            AdditionalAttributes["disabled"] = true;
        }

        CascadedRadioGroup.RerenderRadioBoxes += StateHasChanged;
    }

    /// <summary>
    /// Cleanup component.
    /// </summary>
    public void Dispose()
    {
        if (CascadedRadioGroup != null)
        {
            CascadedRadioGroup.RerenderRadioBoxes -= StateHasChanged;
        }
    }

    /// <summary>
    /// Gets the checked.
    /// </summary>
    /// <value>
    /// The checked.
    /// </value>
    bool? Checked => CascadedRadioGroup?.SelectedValue?.Equals(Value);


    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        if (CascadedInputGroup is null)
        {
            builder.OpenElement(0, "div");
            builder.AddAttribute(1, "class", GetFormCheckClass());
            builder.AddContent(10, content =>
            {
                BuildInput(content);
                BuildLabel(content);
                BuildFeedback(content);
            });
            builder.CloseElement();
        }
        else
        {
            BuildInput(builder);
            BuildLabel(builder);
        }
    }

    protected virtual void BuildInput(RenderTreeBuilder builder)
    {
        builder.OpenRegion(100);
        builder.OpenElement(0, GetHtmlTagName());
        builder.AddAttribute(1, "type", "radio");
        builder.AddAttribute(2, "name", CascadedRadioGroup?.Name);
        builder.AddAttribute(3, "value", BindConverter.FormatValue(Value));
        builder.AddAttribute(4, "checked", Checked);        
        builder.AddAttribute(10, "onchange", CascadedRadioGroup.ChangeEventCallback);
        BuildCommonAttributes(builder);
        builder.CloseElement();
        builder.CloseRegion();
    }

    protected virtual void BuildLabel(RenderTreeBuilder builder)
    {
        if (string.IsNullOrEmpty(Text))
        {
            return;
        }
        builder.OpenElement(0, "label");
        builder.AddAttribute(1, "for", Id);
        builder.AddAttribute(2, "class", "form-check-label");
        builder.AddContent(10, Text);
        builder.CloseElement();
    }

    private void BuildFeedback(RenderTreeBuilder builder)
    {
        if (ChildContent is not null)
        {
            builder.OpenRegion(300);
            builder.AddContent(0, ChildContent);
            builder.CloseRegion();
        }
    }

    string GetFormCheckClass()
    {
        var list = new List<string>() { "form-check" };
        if (CascadedRadioGroup.Inline)
        {
            list.Add("form-check-inline");
        }
        return string.Join(" ", list);
    }
}
